﻿//
// © Algobox Ltd - Benn Eichhorn
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections.Concurrent;

namespace Algobox.Feeds.Finance.Bats.PitchClient 
{
    public class BatsPitchClient : IDisposable
    {
        #region Constructors

        public BatsPitchClient(IBatsMessageHandler callback)
        {
            _callback = callback;

            _messageQueue = new ConcurrentQueue<string>();

            // create message pump thread
            _threadPump = new Thread(new ThreadStart(PumpMessages));
            _threadPump.Name = "BatsPitchClient" + Interlocked.Increment(ref _instanceCount);

            // create reset event handler
            _threadReset = new AutoResetEvent(false);

            // start pump thread
            _threadPump.Start();
        }

        #endregion
//////////////////
        #region Member Variables

        private static long _instanceCount = 0;

        /// <summary>
        /// Message pump thread
        /// </summary>
        
        Thread _threadPump;

        /// <summary>
        /// Used to wake up message pump when there is new data to be processed in the queue
        /// </summary>
        AutoResetEvent _threadReset;

        ConcurrentQueue<string> _messageQueue;

        private IBatsMessageHandler _callback;

        #endregion
//////////////////
        #region Properties

        public int Count { get { return _messageQueue.Count; } }

        #endregion
//////////////////
        #region Functions

        public void EnqueueMessage(string rawMesssge)
        {
            _messageQueue.Enqueue(rawMesssge);
            _threadReset.Set();
        }

        public void EnqueueMessage(ref string rawMesssge)
        {
            _messageQueue.Enqueue(rawMesssge);
            _threadReset.Set();
        }

        /// <summary>
        /// Reads from the message queue, decodes it into an IMessage object and sends out as an event
        /// </summary>
        private void PumpMessages()
        {
            string rawMessage;
            Messages.IMessage message = null;

            while (_threadPump.IsAlive)
            {
                while (_messageQueue.TryDequeue(out rawMessage))
                {
                    if (BatsMessageParser.TryParseMessage(ref rawMessage, ref message))
                        _callback.ProcessMessage(message);
                    else
                        _callback.MessageFailure(message);
                }

                _threadReset.WaitOne();
            }
        }

        #endregion
//////////////////
        #region Enums



        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            _threadPump.Abort();
            _threadReset.Set();
            _threadPump.Join();
            _threadPump = null;
        }

        #endregion
    }
}
